home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / Documentation / Engineering Notes / Views / Defining Views in resources next >
Encoding:
Text File  |  1996-08-16  |  16.4 KB  |  349 lines  |  [TEXT/ttxt]

  1. OpenDoc
  2. Development
  3. Framework
  4.  
  5.                                                                                                                                                                                            
  6. Defining Views in Resources 
  7. ODF Release 1                                                                                                                                                                     
  8.  
  9.  
  10.  
  11. Table of Contents
  12. ------------------
  13. • Introduction
  14. • Typical Views.fr Resource File
  15. • Views Resource Types
  16.     • Frame Layout 
  17.     • Content View Resource
  18.     • Other View Resources
  19.     • Adjusting  the Frame and its SubViews
  20. • Adding a New Resource Type
  21.     • Making Your Class Archivable
  22.     • Adding a Content View Resource
  23.     • Adding Other View Resources
  24. • Loading Your Own Resource
  25.     • Loading a View Layout into a SuperView
  26.     • Loading a Font Resource
  27.  
  28.  
  29. Introduction
  30.  
  31. In ODF release 1 views can be created either by program or in resources.  This document describes how to define your views in resources, using the predefined resource types or after creating new types.
  32.  
  33. See also the folder AppMaker in Tools & Goodies which provides information on the first 3rd party visual tool that can generate ODF view resources. Please check our web page  at /www.devtools.apple.com/odf/ for the latest information on AppMaker and other tools.  
  34.  
  35.  
  36. Typical Views.fr Resource File
  37.  
  38. All ODF samples using views have a project file Views.fr containing the resource definitions.  You can have more than one resource file in your project, as long as the views of each frame are defined in the same file.   ODF cross-platform resource compiler, ODFRC, compiles text resources into binary data in your part.  This data is loaded at runtime when each frame is displayed, either automatically during FW_CFrame::FacetAdded if you provided a resource id in your frame's constructor, or manually when you call CreateSubViewsFromResource(ev, resourceId). 
  39.  
  40. A typical Views.fr starts by including these headers:
  41.  
  42. #ifndef FWRESFIL_K
  43. #include "FWResFil.k"            // some predefined ODFRC types
  44. #endif
  45.  
  46. #ifndef FWVIEWS_FR
  47. #include "FWViews.fr"  // predefined View resource types and macros
  48. #endif
  49.  
  50. #ifndef FWNOTDEF_H
  51. #include "FWNotDef.h"      // Notification constants
  52. #endif
  53.  
  54. #ifndef DEFINES_K
  55. #include "Defines.k"    // Your part's constants
  56. #endif
  57.  
  58. FWViews.fr is the main file to look at for the current resource templates.  It includes FWViews.k containing most view constants and also defines some handy macros.  It is convenient to use #define values in your own file to represent coordinates and fonts, as in Form's View.fr:
  59.  
  60. #define H         FW_FIX(600)
  61. #define V         FW_FIX(1000)
  62.  
  63. #define H1        H + FW_FIX(1)
  64. #define V1        V + FW_FIX(1)
  65.  
  66. // Font not defined in "FWViews.fr"
  67. #define TIMES_12_BOLD        { FW_FIX(12), FW_kBold, "Times" }
  68.  
  69. If your frame uses a custom view class you must define a corresponding resource type, before the frame's resource definition.  See later in this document how to define new resource types.
  70.  
  71. type RFormView : FW_RSuperView(Label='Frmv')
  72. {
  73.       // This form uses 3 radio-clusters (not included in FW_RSuperView)
  74.       FW_RRadioCluster;    
  75.       FW_RRadioCluster;    
  76.       FW_RRadioCluster;
  77. };
  78.  
  79. Finally the frame's views are listed in a FW_RFrameLayout resource (the resource id kFormView is the same one used to create the frame instance in the part's NewFrame method):
  80.  
  81. resource FW_RFrameLayout(kFormView)
  82. {
  83.       {H,V},                          // LayoutSize
  84.       {                                  // Start list of frame's subviews
  85.              RFormView
  86.              (
  87.    ...
  88. }
  89.  
  90.  
  91. View Resource Types
  92.  
  93. Frame Layout 
  94.  
  95. ODF loads only one resource type automatically, FW_RFrameLayout, i.e. this can be the only top-level resource in your file unless you add some code to load other resources manually (see the last section of this document for more information on loading your own resources).
  96.  
  97. FW_RFrameLayout represents the layout of the whole view hierarchy inside a frame plus an optional scroller.  ODF loads this resource the first time a facet is created for that frame.  The frame instance itself was created in your part's NewFrame method, passing the resource id to the FW_CFrame constructor.  At the time OpenDoc needs to display the frame its method FacetAdded is called, and if this is the first facet, this calls in turn CreateSubViewsFromResource(ev, resourceId). 
  98.  
  99. Note: if your frame wasn't created with a resource id the method CreateSubViews is called instead, where you can either load the view resources manually with CreateSubViewsFromResource or create them by program.
  100.  
  101. FW_RFrameLayout starts with a point representing the layout size followed by the list of subviews.   For example:
  102.  
  103.   resource FW_RFrameLayout(kFormView)
  104.   {
  105.        {H,V},                                            // LayoutSize (i.e. virtual extent)
  106.        {                            // ----------------------> Start list of frame's subviews
  107.               RFormView                    // Form's content view
  108.               (
  109.                    ...                    // more subviews
  110.         )
  111.               FW_RScrollBar                      // Horizontal SB
  112.               (     
  113.                      kHorzScrollBarID,                // view id
  114.                      {-FW_ONE, V - FW_SBSIZE, H1 - FW_SBSIZE, V1},    //  SB bounds 
  115.             FW_kHScrollBarBinding,
  116.                   ...
  117.               ),
  118.               FW_RScrollBar                      // Vertical SB
  119.               (     
  120.                 ...
  121.               ),
  122.               FW_RGrowBox
  123.               (     
  124.                ...
  125.               )
  126.         },                 // ----------------------> End list of frame's subviews
  127.      {                                  // 1 of 0 scroller 
  128.                                 FW_RScrollBarScroller        
  129.                                 (
  130.                                                             0,                                                                                            // AutoScrollInset: not used here
  131.                                                             {0, 0}                                                                            // AutoScrollIncrement: 0 = no auto-scroll 
  132.                                                             kHorzScrollBarID,              // Horizontal scroll-bar ID
  133.                                                             kVertScrollBarID               // Vertical scroll-bar ID
  134.                                 ) 
  135.      }
  136.   };
  137.  
  138. The layout size {H,V} is like a virtual extent (not the actual extent of the frame created from this resource!).  Its  value is not important, it is only used as a reference for the subviews defined below.  For instance the scroll bars and grow box are placed at the edges of this layout, with the correct 1 pixel overlap.   When the resource is loaded at runtime the layout size is replaced by the actual extent of the frame which has the effect of adjusting each subview's position and size according to their bindings.
  139.  
  140. After the list of subviews comes a list containing 0 or 1 scroller, depending if this frame's content view scrolls or not.
  141.  
  142. Content View Resource
  143.  
  144. If your frame doesn't contain a separate content view its layout resource is usually a one-level hierarchy composed of simple views, see for example the dialog resource kPasswordDialog in Form's Views.fr.  On the other hand having a separate content view requires using a subtype of FW_RSuperView because the content view is a subclass of FW_CSuperView.  See the section below, "Adding a New Resource Type".
  145.  
  146. Other View Resources
  147.  
  148. Each class of views is described in a separate engineering note in the same folder.  See these documents for more information on resources for Controls, Edit Views, List Boxes, etc.   The file FWViews.fr also contains comments describing the fields of each resource type.
  149.  
  150. Adjusting  the Frame and its SubViews
  151.  
  152. Everything you need to create your frame's view hierarchy can be defined in a single FW_RFrameLayout resource, except for the frame's position and size that are set by the container part or the window.  You can also make additional modifications right after loading the resource in your frame's PostCreateViewFromStream method.  Here is a list of things that can be done in this method:
  153.  
  154. • Create objects that don't have any resource types, such as a FW_CViewTabber.
  155. • Remove scroll bars when the frame is not the root frame.
  156. • Connect notifiers other than controls to your frame.
  157. • Disable controls.
  158. • More generally, perform any kind of initialization on the newly created views.
  159.  
  160. Once loaded any view can be accessed through its view id, like this:
  161.  
  162.       // ----- Disable the "Remove" button by default
  163.       FW_CButton* rmButton = (FW_CButton*) parentView->FindViewById(ev, kRemoveButtonID);
  164.       rmButton->Disable(ev);
  165.  
  166. Note: while your part is in development you may want to use RTTI instead of a direct cast to be able to catch errors on the view ids.
  167.  
  168.  
  169. Adding a New Resource Type (Making Your Class Archivable)
  170.  
  171. Every time you subclass a view class and want to store its instances in your frame's layout resource you need to define a new resource type and make your class archivable.  This happens in two typical cases: your frame has a separate content view (it is always a subclass of FW_CSuperView) or you want to customize one of the simple views that are not superviews.
  172.  
  173. Note: for more information on the syntax used in resource files see  the ODFRC Reference Manual in the Documentation folder and the various types defined in FWViews.fr.
  174.  
  175. Making Your Class Archivable
  176.  
  177. In order to load a class from resources you need to declare it to the ODF Archiver.  This is done by using the macro FW_REGISTER_ARCHIVABLE_CLASS in the source of this class and implementing the following methods: Create, Destroy, Flatten and InitializeFromStream.
  178.  
  179. FW_REGISTER_ARCHIVABLE_CLASS is described in the Streams Subsystem API Reference.  For example the Container sample registers its content view class, CContainerView, at the top of View.cpp as follows:
  180.  
  181. FW_DEFINE_CLASS_M1(CContainerView, FW_CSuperView)
  182.  
  183. const FW_ClassTypeConstant LContainerView = FW_TYPE_CONSTANT('c','t','v','w');
  184. FW_REGISTER_ARCHIVABLE_CLASS(LContainerView, CContainerView, CContainerView::Create, 
  185.                             FW_CView::Read, CContainerView::Destroy, FW_CView::Write)
  186.  
  187. LContainerView is the class constant also used in the resource type definition.  It must be unique among all class labels registered with the Archiver (ODF reserves labels which are all lowercase letters or digits, so, to avoid conflict, your label should contain at least an uppercase letter or another character).
  188.  
  189. • CContainerView::Create is a static method for creating the object during a two-step input.
  190. • CContainerView::Destroy is a static method for deleting the object in case the initialization fails during a two-step input.
  191. • FW_CView::Read and FW_CView::Write are static methods of FW_CView for initializing and outputing any view.
  192.  
  193. As the following code sample shows, Create is a simple call to the class minimal constructor and Destroy is a simple delete call.  
  194.  
  195. void* CContainerView::Create(FW_CReadableStream& stream, FW_ClassTypeConstant type)
  196. {
  197. FW_UNUSED(stream);
  198. FW_UNUSED(type);
  199. FW_SOMEnvironment ev;
  200.     
  201.      // Call minimal constructor.  Data will be initialized in InitializeFromStream
  202.      return new CContainerView(ev);
  203. }
  204.  
  205. void CContainerView::Destroy(void* object, FW_ClassTypeConstant type)
  206. {
  207. FW_UNUSED(type);
  208.       CContainerView* self = (CContainerView*) object;
  209.       delete self;
  210. }
  211.  
  212. Once the object is created with Create, the Archiver reads the stream with FW_CView::Read which in turn calls your class virtual method InitializeFromStream (2 steps initialization).  InitializeFromStream should call inherited first and then perform additional intializations for this class.  The same way, when outputing the object, the Archiver calls FW_CView::Write which in turn calls your class virtual method Flatten.
  213.  
  214. Adding a Content View Resource
  215.  
  216. As mentioned earlier having a separate content view requires using a subtype of FW_RSuperView.  A simple content view such as the one in Container doesn't add any field to its base type, the definition in Views.fr is straightforward, the only addition is the class label 'ctvw' that was used in the macro FW_REGISTER_ARCHIVABLE_CLASS.
  217.  
  218. type RContainerView : FW_RSuperView(Label='ctvw')
  219. {
  220. };
  221.  
  222. The initialization of the class is a simple call to the base class to read in the resource. In this example InitializeFromStream contains additional code to get pointers to the frame itself, to the part and to the content (here the frame could be accessed more easily with GetFrame(ev) because the hierarchy is already built at this point).
  223.  
  224. void CContainerView::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  225. {
  226.       // Read-in the base resource first
  227.       FW_CSuperView::InitializeFromStream(ev, stream);
  228.     
  229.       // Get a pointer to the frame which was pre-registered
  230.       FW_OObjectRegistry*    registry = stream.GetRegistry();
  231.       FW_CFrame* frame = (FW_CFrame*) registry->LookupByID(ev, FW_kPreregisteredFrameObject);
  232.       FW_ASSERT(frame != NULL);
  233.     
  234.       // Set the fContainerFrame, fContainerPart & fPartContent fields
  235.       fContainerFrame = FW_DYNAMIC_CAST(CContainerFrame, frame);
  236.       FW_ASSERT(fContainerFrame != NULL);
  237.     
  238.       FW_CEmbeddingPart* part = fContainerFrame->GetPart(ev);
  239.       fContainerPart = FW_DYNAMIC_CAST(CContainerPart, part);
  240.       FW_ASSERT(fContainerPart != NULL);
  241.  
  242.       fPartContent = fContainerPart->GetPartContent();
  243.       FW_ASSERT(fPartContent != NULL);
  244. }
  245.  
  246. Similarily the Container view doesn't have any custom fields to stream out to. Its flatten method is identical to that of the base class:
  247.  
  248. void CContainerView::Flatten(Environment* ev, FW_CWritableStream& archive) const
  249. {
  250.       FW_CSuperView::Flatten(ev, archive);
  251. }
  252.  
  253. Note:  when your content view doesn't add any field and your InitializeFromStream or Flatten methods just call the base class you don't need to implement them of course. We left them in our samples for your convenience since you may use this code as a starting point.
  254.  
  255. In the case of Form the content view type adds 3 custom fields representing the 3 radio cluster objects:
  256.  
  257. type RFormView : FW_RSuperView(Label='Frmv')
  258. {
  259.       // This form uses 3 radio-clusters (not included in FW_RSuperView)
  260.       // The code to load them is in CFormView::InitializeFromStream().
  261.     
  262.       FW_RRadioCluster;    
  263.       FW_RRadioCluster;    
  264.       FW_RRadioCluster;
  265. };
  266.  
  267. So the InitializeFromStream method must read this data from the stream after calling the base class:
  268.  
  269. void CFormView::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  270. {
  271.       // Read-in the base resource first
  272.    FW_CSuperView::InitializeFromStream(ev, stream);
  273.     
  274.       // Read-in the 3 radio-clusters defined in our RFormView type in "Views.fr"
  275.       // and initialize our radio-clusters array for future use.
  276.       for (int i = 0; i < kNumRadioClusters; i++) 
  277.       {
  278.            FW_READ_DYNAMIC_OBJECT(stream, &fRadioClusters[i], FW_CRadioCluster);
  279.       }    
  280. }
  281.  
  282. Note: CFormView::Flatten is not completed yet, it should stream out the 3 cluster objects after the superview resource.
  283.  
  284. Adding Other View Resources
  285.  
  286. You need to follow a similar implementation for defining other view resource types, for instance when subclassing light views like controls or edit views.   Form contains a custom edit view whose resource types adds 3 fields to the default type:
  287.  
  288. type RScrollEdit : FW_REditView(Label='Sedv')
  289. {
  290. HorizViewID:
  291.       longint;              // Horizontal scrollbar id, or 0 for no scrollbar
  292. VertViewID:
  293.       longint;              // Vertical scrollbar id, or 0 for no scrollbar
  294. TextWidth:
  295.       FW_RFixed;            // text width (or 0 to use same width as view)
  296. };
  297.  
  298. The initialization method reads the resource stream as follows:
  299.  
  300. void CScrollEdit::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  301. {
  302.       FW_CEditView::InitializeFromStream(ev, stream);
  303.     
  304.       ODID horizScrollBarID;
  305.       ODID vertScrollBarID;
  306.       stream >> horizScrollBarID >> vertScrollBarID >> fWidth;
  307.    ...
  308. }
  309.  
  310. And it writes it back as follows:
  311.  
  312. void CScrollEdit::Flatten(Environment* ev, FW_CWritableStream& stream) const
  313. {
  314.        FW_CEditView::Flatten(ev, stream);
  315.  
  316.        ODID horizScrollBarID = ...
  317.        ODID vertScrollBarID = ...
  318.  
  319.        stream << horizScrollBarID << vertScrollBarID << fWidth;
  320. }
  321.  
  322.  
  323. Loading Your Own Resource
  324.  
  325. Loading a View Layout into a SuperView
  326.  
  327. You can create the subview hierarchy of an existing superview by loading its FW_RViewLayout resource: this is the base type for FW_RFrameLayout, it contains the same virtual extent point and list of subviews, but no scroller field.
  328.  
  329.    mySuperView->CreateSubViewsFromResource(ev,  resourceId);
  330.  
  331. Loading a Font Resource
  332.  
  333. This is how you would load a font resource into a FW_CFont object:
  334.  
  335.    FW_CSharedLibraryResourceFile resFile(ev,      
  336.                                    GetFrame(ev)->GetPart(ev)->GetPartInstance(ev));
  337.    FW_PResource fontResource(ev, resFile, id, kFontType);
  338.    FW_PResourceSink sink(ev, fontResource);
  339.  
  340.    FW_CFont font;
  341.    stream >> font;
  342.  
  343.  
  344. See also the description of the FW_READ_DYNAMIC_OBJECT macro in the  Streams Subsystem API Reference.
  345.  
  346.  
  347.  
  348. © 1993 - 1996 Apple Computer, Inc. All rights reserved.
  349. Apple, the Apple Logo, Macintosh, and OpenDoc are trademarks of Apple Computer, Inc., registered in the United States and other countries.